1. Field of the Invention
The present invention relates to translation of Java bytecode, and more particularly, to a Java bytecode translation method in which Java bytecode is translated, thereby quickly accessing a field in a Java class, and a Java interpreter performing the Java bytecode translation method.
2. Description of the Related Art
Although the Java programming language has rapidly proliferated as a standard object-oriented programming language since its advent in the middle of the 1990s, it renders several disadvantages. Such a disadvantage includes a lower execution speed than the C programming language or the C++ programming language. In order to increase the execution speed of the Java programming language, a dynamic code generation system, such as a Java virtual machine adopting a just-in-time (JIT) compiler, and a static code generation system, such as a Java virtual machine adopting an ahead-of-time (AOT) compiler, have been developed.
A Java platform consists of a Java virtual machine and a plurality of classes. Each class consists of information regarding a data structure of the class, field information, and method information. Execution code of a method is written in bytecodes independent of a hardware device or an operating system.
Conventional Java virtual machines can be classified into interpreter-type Java virtual machines, JIT compiler-type Java virtual machines, interpreter-and-JIT compiler-type Java virtual machines, and AOT compiler-type Java virtual machines according to the types of their respective execution engines.
An interpreter-type Java virtual machine interprets a plurality of bytecodes of a method to be executed one by one, and executes an application program of the method.
A JIT compiler-type Java virtual machine compiles the bytecodes of the method to obtain machine codes dependent upon a Java platform, and executes the machine codes to execute the application program of the method.
FIG. 1 is a diagram illustrating a conventional Java virtual machine 100 and a Java class 160.
Referring to FIG. 1, the Java virtual machine 100 includes an interpreter 110 which sequentially executes a plurality of bytecodes, a JIT or AOT compiler 120, a class loader 130 which loads a java class to be executed therein, a runtime system 140 which combines the whole components, that is, the interpreter 110, the JIT or AOT compiler 120, and the class loader 130 and runs the components, and a garbage collector 150 which manages a Java object that has already been used.
The Java class 160 includes a plurality of application classes 170 which are defined and executed by a user, and a plurality of system classes 180 which are predefined to specify a variety of basic functions to be provided by the Java programming language.
FIG. 2 is a diagram illustrating the format of a conventional Java class file 200.
Referring to FIG. 2, the class file 200 includes basic information regarding the class file 200, a plurality of constants, an interface definition, field information, method information, and various attribute information.
A byte stream, which is also called bytecode, to be executed by an interpreter, is defined in the method information. Bytecode is obtained by compiling a file containing text messages written in a Java primitive language (e.g., a file with a file name extension ‘java’).
Bytecode is similar to a program module ready to be executed in that it is executed in a computer in units of bytes. However, bytecode instructions are actual instructions transmitted to a Java virtual machine that is a logical and abstract machine. Bytecode may be compiled by a JIT compiler so as to be compatible with a specific system platform, instead of being interpreted in units of bytes, in which case, the execution speed of a Java program is considerably increased.
One approach of increasing the execution speed of the Java program in an interpreter is to use a threaded interpreter technique in which the address of an opcode handler in an interpreter is written to a portion corresponding to an opcode in a bytecode format.
FIG. 3 is a diagram illustrating bytecode executed by a conventional Java virtual machine.
Referring to FIG. 3, a bytecode is defined as a byte stream in each method and is a type of intermediate code obtainable by compiling a file written in the Java programming language. Therefore, bytecode is similar to a ready-executable software program module in that one sentence is executed in a computer each time a compiling operation is made. Bytecode instructions are actually transmitted to a Java virtual machine which is a logical and abstract machine.
A single line of bytecode instructions contains a one-byte opcode for identifying an operation to be executed, and operands. An opcode may be followed by one or more operands. That is to say, the opcode and the operands are both stored in units of bytes, so that they may be represented by a number of successive bytes in order to express an operand having a size of one or more bytes. For example, a 16-bit operand may be represented by two successive bytes, and a 32-bit operand may be represented by four successive bytes.
The first row of Table illustrated in FIG. 3 shows hexadecimal values of bytecodes, and the second row of the table as illustrated in FIG. 3 indicates whether the bytecodes in the first row of the table are opcodes or operands.
FIG. 4 is a flowchart illustrating the loading and executing of a class by a conventional Java virtual machine.
Referring to FIG. 4, in operation S400, a class loader of a Java virtual machine loads an application class therein. In operation S410, the Java virtual machine performs a class linking operation. In operation S420, the Java virtual machine performs a class initialization operation. Thereafter, the Java virtual machine stores data obtained from the class linking operation and the class initialization operation in a data structure of a runtime system. In operation S430, an execution engine, such as an interpreter or a JIT compiler, executes a method.
FIG. 5 is a flowchart illustrating a bytecode execution method performed by a conventional Java interpreter.
Referring to FIG. 5, in operation S500, the Java interpreter calls a method. In operation S510, the Java interpreter increases a count value of a program counter designating one of a plurality of bytecodes of the method. In operation S520, the Java interpreter determines whether a bytecode (hereinafter referred to as the current bytecode) designated by a current count value of the program counter is the last bytecode of the method. In operation S530, if the current bytecode is determined not to be the last bytecode of the method in operation S520, the Java interpreter fetches a one-byte opcode. In operations S540 and S550, the Java interpreter moves to a handler corresponding to the opcode and executes the handler. Here, a handler is code defined by a Java interpreter to specify what action a Java virtual machine must take. Operations S510 through S550 are carried out as many times as there are bytecodes in the method, thereby completing an entire interpretation operation in operation S560.
The conventional bytecode execution method as illustrated in FIG. 5 may be represented in pseudo code as follows.
Loop {    Op = *pc++;    switch (Op) {        case op_1:            // op_1's implementation            break;        case op_2:            // op_2's implementation            break;        case op_3:            // op_3's implementation            break;    ...        }
If an operand needed by an opcode in a handler consists of more than one byte, its value may be stored as a series of successive bytes. The successive bytes are reconstructed into a single meaningful value through bitwise OR and shift operations. For example, assuming that an opcode A in a CPU using little endian needs an operand having a 32-bit value, the operand may be represented by a series of four successive bytes, i.e., bytes 1 through 4. Therefore, first through eighth bits of the operand may be represented by byte 4, ninth through sixteenth bits of the operand may be represented by byte 3, seventeenth through twenty fourth bits of the operand may be represented by byte 2, and twenty fifth through thirty second bits of the operand may be represented by byte 1.
Therefore, the 32-bit value needed by the opcode A may be calculated through the following operation: (byte1<<24)|(byte2<<16)| (byte3<<8)| byte4. In a conventional Java virtual machine, this type of operand combination occurs whenever a method is executed.
In general, the reading/writing of field values from/to a Java class is frequently carried out when a method is executed. To perform this, bytecodes ‘getfield’ and ‘putfield’ are defined.
The bytecodes ‘getfield’ and ‘putfield’ are used to read/write the value of the bytecodes directly accompanied by an index in a predetermined field of a predetermined class. Usually, the bytecodes ‘getfield’ and ‘putfield’ are used for reading/writing a field value from/to a class currently being executed and are accompanied by bytecode ‘aload_0’.
In other words, the bytecode ‘getfield’ following bytecode ‘aload_0’ is used for accessing a field in its class. The bytecode ‘getfield’ may be accompanied by bytecode ‘aload_1’, ‘aload_2’, or ‘aload_3’ instead of ‘aload_0’. In this case, the bytecode ‘getfield’ can be used for obtaining a field value from a class other than its designated class.
In short, the bytecode ‘getfield’ may be used for obtaining different class objects by being accompanied by different types of bytecodes, but how the bytecode ‘getfield’ obtains a class object is always the same regardless of what bytecode it follows.
FIG. 6 is a flowchart illustrating a conventional bytecode execution method of accessing a field performed by a conventional Java interpreter.
Referring to FIG. 6, in operation S610, bytecode aload_n is executed and an n-th Java object in a local variable array (i.e., a Java class currently being executed if n=0) is stored in a stack.
In operation S620, the n-th Java object is extracted from bytecode getfield that follows the bytecode aload_n, and index information designating a field to be accessed is obtained from the n-th Java object. In operation S630, the address information of the field is calculated. In operation S640, a field value is obtained from the field address information and then is stored in the stack.
Despite so many advantages, including platform independence, the relatively slow execution speed of Java has made the Java platform problematic. In particular, an interpreter-type Java virtual machine ends up having a relatively low execution speed. Especially, the execution speed of a Java virtual machine is several times or dozens of times lower in an interpretation approach than in a platform-based native code generation approach in which native code is generated to be compatible with a Java platform.
Therefore, a variety of technologies, such as a JIT compilation technology, have been developed to enhance the execution speed of a Java virtual machine. However, in a conventional compilation method, compiled codes and intermediate codes always need to be stored in memories, and thus, a considerable amount of overhead may be generated in the middle of a compilation operation according to the degree to which a Java virtual machine is optimized. Therefore, platforms with a highly restricted memory capacity, such as embedded systems, still use the interpreter approach.
In addition, in a conventional real-time profiling-based selective compilation method, the so-called ‘Hot Spot’ algorithm, the interpreter-type approach is also used especially when a profiling operation is performed.
As described above, the interpreter-type approach is still adopted in various compilation methods in spite of its disadvantage, i.e., a slow execution speed. In light of the foregoing, there still exists a need for an improved execution speed.